#include "object.h"
#include <iostream>
#include <GL/gl.h>
#include <cmath>
#include "defines/rotation.h"

Object::Object(int _id, int _type, bool _primitive) : id(_id), type(_type), primitive(_primitive){
    color = Color(1.0, 1.0, 0.0, 1.0);
    selected = false;
    rotationX = R0;
    rotationY = R0;
    rotationZ = R0;
}

Object::Object(const Color &_c, int _id, int _type, bool _primitive) : id(_id), color(_c), type(_type), primitive(_primitive){
    selected = false;
    rotationX = R0;
    rotationY = R0;
    rotationZ = R0;
}

Object::~Object(){
}

int Object::getId() const{
    return id;
}

void Object::setId(int _id){
    id = _id;
}

const Color &Object::getColor() const{
    return color;
}

void Object::setColor(const Color &_c){
    color = _c;
}

bool Object::isSelected() const{
    return selected;
}

void Object::select(bool _b){
    selected = _b;
}

bool Object::isPrimitive() const{
    return primitive;
}

int Object::getType() const{
    return type;
}

void Object::rotate(int _x, int _y, int _z){
    rotationX += _x;
    if(rotationX > 3) rotationX = rotationX - 4;

    rotationY += _y;
    if(rotationY > 3) rotationY = rotationY - 4;

    rotationZ += _z;
    if(rotationZ > 3) rotationZ = rotationZ - 4;

//    std::cout <<"Rotação total: \n\t - X: " << rotationX << "\n\t - Y: " << rotationY << "\n\t - Z: " << rotationZ <<std::endl;
}

int Object::getRotationX() const{
    return rotationX;
}

int Object::getRotationY() const{
    return rotationY;
}

int Object::getRotationZ() const{
    return rotationZ;
}

void Object::setBoxPoints(const Vector3D &_min, const Vector3D &_max, Vector3D *_point) const{
    _point[0] = _min;
    _point[1] = Vector3D(_max.x, _min.y, _min.z);
    _point[2] = Vector3D(_min.x, _min.y, _max.z);
    _point[3] = Vector3D(_max.x, _min.y, _max.z);
    _point[4] = Vector3D(_min.x, _max.y, _min.z);
    _point[5] = Vector3D(_max.x, _max.y, _min.z);
    _point[6] = Vector3D(_min.x, _max.y, _max.z);
    _point[7] = _max;
}

void Object::drawBox(bool _wireframe, const Vector3D &_min, const Vector3D &_max, bool _useParentColor, const Color &_parentColor) const{
    if(_wireframe){
        glDisable(GL_LIGHT0);
        glDisable(GL_LIGHTING);

        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
        glDisable(GL_CULL_FACE);

        if(!selected) glLineWidth(2);
    }

    Vector3D point[8];
    setBoxPoints(_min, _max, point);

	glPushMatrix();
	glRotated(rotationX * 90, 1.0, 0.0, 0.0);
	glRotated(rotationY * 90, 0.0, 1.0, 0.0);
	glRotated(rotationZ * 90, 0.0, 0.0, 1.0);

    Vector3D normal;
    glBegin(GL_QUADS);
        Color color_ = chooseColor(_wireframe, _useParentColor, _parentColor);
        glColor4d(color_.red, color_.green, color_.blue, color_.alpha);

    //parte de baixo
        normal = ((point[4] - point[0]).crossProduct(point[1] - point[0])).normalize();
        glNormal3f(normal.x, normal.y, normal.z);
        glVertex3f(point[0].x, point[0].y, point[0].z);
        glVertex3f(point[4].x, point[4].y, point[4].z);
        glVertex3f(point[5].x, point[5].y, point[5].z);
        glVertex3f(point[1].x, point[1].y, point[1].z);


    //parte de cima
        glNormal3f(-normal.x, -normal.y, -normal.z);
        glVertex3f(point[2].x, point[2].y, point[2].z);
        glVertex3f(point[3].x, point[3].y, point[3].z);
        glVertex3f(point[7].x, point[7].y, point[7].z);
        glVertex3f(point[6].x, point[6].y, point[6].z);

    //parte de esquerda
        normal = ((point[2] - point[0]).crossProduct(point[4] - point[0])).normalize();
        glNormal3f(normal.x, normal.y, normal.z);
        glVertex3f(point[0].x, point[0].y, point[0].z);
        glVertex3f(point[2].x, point[2].y, point[2].z);
        glVertex3f(point[6].x, point[6].y, point[6].z);
        glVertex3f(point[4].x, point[4].y, point[4].z);

    //parte de direita
        glNormal3f(-normal.x, -normal.y, -normal.z);
        glVertex3f(point[1].x, point[1].y, point[1].z);
        glVertex3f(point[5].x, point[5].y, point[5].z);
        glVertex3f(point[7].x, point[7].y, point[7].z);
        glVertex3f(point[3].x, point[3].y, point[3].z);

    //parte de frente
        normal = ((point[1] - point[0]).crossProduct(point[2] - point[0])).normalize();
        glNormal3f(normal.x, normal.y, normal.z);
        glVertex3f(point[0].x, point[0].y, point[0].z);
        glVertex3f(point[1].x, point[1].y, point[1].z);
        glVertex3f(point[3].x, point[3].y, point[3].z);
        glVertex3f(point[2].x, point[2].y, point[2].z);

    //parte de tras
        glNormal3f(-normal.x, -normal.y, -normal.z);
        glVertex3f(point[4].x, point[4].y, point[4].z);
        glVertex3f(point[6].x, point[6].y, point[6].z);
        glVertex3f(point[7].x, point[7].y, point[7].z);
        glVertex3f(point[5].x, point[5].y, point[5].z);
    glEnd();

	glPopMatrix();

    if(_wireframe){
        glLineWidth(1);

        glEnable(GL_LIGHT0);
        glEnable(GL_LIGHTING);

        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
        glEnable(GL_CULL_FACE);
    }
}

int Object::classify(Vector3D */*_octreePoint*/) const{
    std::cout << "Classify default em objeto! \n\tChamado pelo objeto " << id <<std::endl;
    return 0;
}

double Object::toRad(double _x) const{
    return (_x * M_PI)/180.0;
}

Color Object::chooseColor(bool _wireframe, bool _useParentColor, const Color& _parentColor) const{
    Color result;

    if(_useParentColor) result = _parentColor;
    else result = color;

    if(_wireframe && selected){
//        if(result != Color(1,0,0,1)) result = Color(1, 0, 0, 1);
//        else result = Color(1, 1, 1, 1);
        if( (result.red >= 0.8) && (result.green <= 0.2) && (result.blue <= 0.2) && (result.alpha >= 0.8) ) result = Color(1, 1, 1, 1);
        else result = Color(1, 0, 0, 1);
    }

    return result;
}
